package com.moke.format
{

	/**
	 * 日期格式化工具
	 *
	 */
	public class DateFormat
	{

		public static const DAYS:Vector.<String>=Vector.<String>(["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]);
		public static const DAYS_ABBREVIATED:Vector.<String>=Vector.<String>(["Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"]);
		public static const MONTHS:Vector.<String>=Vector.<String>(["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]);
		public static const MONTHS_ABBREVIATED:Vector.<String>=Vector.<String>(["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]);
		public static const DAYSINMONTH:Vector.<int>=Vector.<int>([31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]);

		public static function formatMilliseconds(nMilliseconds:Number):String
		{
			var nSeconds:Number=nMilliseconds / 1000;
			return formatSeconds(nSeconds);
		}

		public static function formatSeconds(nTotalSeconds:Number):String
		{
			var nfFormatter:NumberFormat=new NumberFormat("00");
			var sMinutes:String=nfFormatter.format(Math.floor(nTotalSeconds / 60));
			var sSeconds:String=nfFormatter.format(Math.round(nTotalSeconds - (parseInt(sMinutes) * 60)));
			return sMinutes + ":" + sSeconds;
		}

		private var _sMask:String; // 格式掩码

		public function DateFormat(sMask:String)
		{
			_sMask=sMask;
		}

		public function format(dDate:Date):String
		{
			var aMask:Vector.<MaskInfo>=getMaskElements();
			var aFormatted:Array=new Array();
			var nfFormatter:NumberFormat ;
			var nHours:Number ;
			for (var i:Number=0; i < aMask.length; i++)
			{
				switch (aMask[i].element)
				{
					case "a":
						if (dDate.getHours() < 12)
						{
							aFormatted.push("am");
						}
						else
						{
							aFormatted.push("pm");
						}
						break;
					case "A":
						if (dDate.getHours() < 12)
						{
							aFormatted.push("AM");
						}
						else
						{
							aFormatted.push("PM");
						}
						break;
					case "d":
						aFormatted.push(dDate.getDate());
						break;
					case "D":
						aFormatted.push(DateFormat.DAYS_ABBREVIATED[dDate.getDay()]);
						break;
					case "F":
						aFormatted.push(DateFormat.MONTHS[dDate.getMonth()]);
						break;
					case "g":
						nHours=dDate.getHours();
						if (nHours == 12)
						{
							aFormatted.push(12);
						}
						else if (nHours <= 12)
						{
							aFormatted.push(nHours);
						}
						else
						{
							aFormatted.push(nHours - 12);
						}
						break;
					case "G":
						aFormatted.push(dDate.getHours());
						break;
					case "h":
						nfFormatter=new NumberFormat("00");
						nHours=dDate.getHours();
						if (nHours == 12)
						{
							aFormatted.push(12);
						}
						else if (nHours <= 12)
						{
							aFormatted.push(nfFormatter.format(nHours));
						}
						else
						{
							aFormatted.push(nfFormatter.format(nHours - 12));
						}
						break;
					case "H":
						nfFormatter=new NumberFormat("00");
						aFormatted.push(nfFormatter.format(dDate.getHours()));
						break;
					case "i":
						nfFormatter=new NumberFormat("00");
						aFormatted.push(nfFormatter.format(dDate.getMinutes()));
						break;
					case "j":
						aFormatted.push(dDate.getDate());
						break;
					case "l":
						aFormatted.push(DateFormat.DAYS[dDate.getDay()]);
						break;
					case "m":
						nfFormatter=new NumberFormat("00");
						aFormatted.push(nfFormatter.format(dDate.getMonth() + 1));
						break;
					case "M":
						aFormatted.push(DateFormat.MONTHS_ABBREVIATED[dDate.getMonth()]);
						break;
					case "n":
						aFormatted.push(dDate.getMonth() + 1);
						break;
					case "s":
						nfFormatter=new NumberFormat("00");
						aFormatted.push(nfFormatter.format(dDate.getSeconds()));
						break;
					case "t":
						aFormatted.push(DateFormat.DAYSINMONTH[dDate.getMonth()]);
						break;
					case "w":
						aFormatted.push(dDate.getDay());
						break;
					case "y":
						aFormatted.push(String(dDate.getFullYear()).substring(2));
						break;
					case "Y":
						aFormatted.push(dDate.getFullYear());
						break;
					case "\\":
						aFormatted.push(aMask[i].element + ((aMask[i + 1].element == null) ? "" : aMask[i + 1].element));
						i++;
						break;
					default:
						aFormatted.push(aMask[i].element);
				}
			}
			return aFormatted.join("");
		}

		public function parse(sDate:String):Date
		{
			var aMask:Vector.<MaskInfo>=getMaskElements(true);
			var nIndex:Number;
			var sDate:String;
			for (var k:Number=0; k < aMask.length; k++)
			{
				nIndex=sDate.indexOf(aMask[k].element);
				if (aMask[k].type == "quoted")
				{
					if (nIndex != -1)
					{
						sDate=sDate.substring(0, nIndex) + " " + sDate.substring(nIndex + aMask[k].element.length);
						aMask.splice(k, 1);
						k--;
					}
				}
			}
			
			var reParser:RegExp=new RegExp("[^a-zA-Z0-9]+");
			var aElements:Array=sDate.split(reParser);
			var dDate:Date=new Date(0, 0, 0, 0, 0, 0, 0);
			var sAMPM:String;
			var sElement:String;
			var sMonth:String ;
			
			for (var i:Number=0; i < aMask.length; i++)
			{
				sElement=String(aElements.shift());
				switch (aMask[i].element)
				{
					case "a":
					case "A":
						sAMPM=sElement.toLowerCase();
						break;
					case "d":
						dDate.setDate(parseInt(sElement));
						break;
					case "F":
						sMonth=aElements.shift().toLowerCase();
						for (var j:Number=0; j < DateFormat.MONTHS.length; j++)
						{
							if (sMonth == DateFormat.MONTHS[j].toLowerCase())
							{
								dDate.setMonth(j);
								break;
							}
						}
						break;
					case "g":
					case "G":
					case "h":
					case "H":
						dDate.setHours(parseInt(sElement));
						break;
					case "i":
						dDate.setMinutes(parseInt(sElement));
						break;
					case "j":
						dDate.setDate(parseInt(sElement));
						break;
					case "m":
					case "n":
						dDate.setMonth(parseInt(sElement) - 1);
						break;
					case "M":
						sMonth=sElement.toLowerCase();
						for (var m:Number=0; m < DateFormat.MONTHS_ABBREVIATED.length; m++)
						{
							if (DateFormat.MONTHS_ABBREVIATED[m].toLowerCase() == sMonth)
							{
								dDate.setMonth(m);
								break;
							}
						}
						break;
					case "s":
						dDate.setSeconds(parseInt(sElement));
						break;
					case "y":
						dDate.setFullYear(2000 + (parseInt(sElement)));
						break;
					case "Y":
						dDate.setFullYear(parseInt(sElement));
						break;
				}
			}
			if (sAMPM == "pm")
			{
				if (dDate.getHours() < 12)
				{
					dDate.setHours(dDate.getHours() + 12);
				}
			}
			else if (sAMPM == "am")
			{
				if (dDate.getHours() == 12)
				{
					dDate.setHours(0);
				}
			}
			return dDate;
		}

		private function getMaskElements(bIgnoreNonAlpha:Boolean=false):Vector.<MaskInfo>
		{
			var aMaskElements:Vector.<String>=Vector.<String>(_sMask.split("'"));
			var aMask:Vector.<MaskInfo>=new Vector.<MaskInfo>();
			var aTemporary:Array;
			var reParser:RegExp=new RegExp("[a-zA-Z]");
			for (var i:Number=0; i < aMaskElements.length; i++)
			{
				if (i % 2 != 0)
				{
					aMask.push(new MaskInfo("quoted", aMaskElements[i]));
				}
				else
				{
					aTemporary=aMaskElements[i].split("");
					for (var j:Number=0; j < aTemporary.length; j++)
					{
						if (reParser.test(aTemporary[j]) && bIgnoreNonAlpha)
						{
							aMask.push(new MaskInfo("regular", aTemporary[j]));
						}
						else if (!bIgnoreNonAlpha)
						{
							aMask.push(new MaskInfo("regular", aTemporary[j]));
						}
					}
				}
			}
			return aMask;
		}

	}
}

class MaskInfo
{
	public var type:String;
	public var element:String;

	public function MaskInfo(type:String, element:String)
	{
		this.type=type;
		this.element=element;
	}

}
